package avicit.bdp.dgs.mdm.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.VersionUtil;
import avicit.bdp.dgs.mdm.dao.TableDAO;
import avicit.bdp.dgs.mdm.dto.ColumnDTO;
import avicit.bdp.dgs.mdm.dto.TableDTO;
import avicit.bdp.dgs.mdm.utils.constants.Constants;
import avicit.bdp.dgs.mdm.utils.enums.EnableState;
import avicit.bdp.dgs.mdm.utils.enums.ModelState;
import avicit.bdp.dgs.mdm.utils.enums.ModelType;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.impl.SystemConstant;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.rest.msg.QueryRespBean;
import com.github.pagehelper.Page;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2023-12-04
 * @类说明：TableService
 * @修改记录：
 * @注意事项：
 * @主要功能：模型Service
 */
@Service
public class TableService extends BaseService<TableDAO, TableDTO> {
    private static final Logger logger = LoggerFactory.getLogger(TableService.class);

    @Autowired
    private ColumnService columnService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private ConvertColumnClient convertColumnClient;

    /**
     * 新增模型
     *
     * @param tableDTO
     * @return
     */
    @Transactional
    public String addModel(TableDTO tableDTO) {
        checkAddValidity(tableDTO);

        return saveModel2Db(tableDTO);
    }

    /**
     * 删除/批量删除模型，多个id使用英文逗号隔开
     *
     * @param id
     * @return
     */
    @Transactional
    public int deleteModel(String id) {
        if (StringUtils.isBlank(id)) {
            return 0;
        }

//        return this.mapper.deleteModelByCond(Arrays.asList(id.trim().split(Constants.COMMA)));
        return deleteModelInner(id);
    }

    /**
     * 修改模型
     *
     * @param tableDTO
     * @return
     */
    @Transactional
    public boolean updateModel(TableDTO tableDTO) {
        checkUpdateValidity(tableDTO);

        updateModel2Db(tableDTO);

        return true;
    }

    /**
     * 查询模型详情
     *
     * @param id 模型ID
     * @return
     */
    public TableDTO getModelDetail(String id) {
        if (StringUtils.isBlank(id)) {
            return null;
        }

        TableDTO queryRet = this.mapper.getModelDetail(id);
        if (queryRet == null) {
            throw new BusinessException("未找到模型，id：" + id);
        }

        valueConvert(Arrays.asList(queryRet));

        return queryRet;
    }

    /**
     * 分页查询模型
     *
     * @param topicId
     * @param keyWords
     * @param code
     * @param status
     * @param pageNo
     * @param pageSize
     * @return
     */
    public QueryRespBean<TableDTO> queryModel(String topicId, String keyWords, String code, Integer status, Integer pageNo, Integer pageSize) {
        QueryRespBean<TableDTO> queryRespBean = new QueryRespBean<>();

        // 根节点特殊处理
        if (StringUtils.isNotEmpty(topicId) && topicId.equals("-1")) {
            topicId = null;
        }

        com.github.pagehelper.PageHelper.startPage(pageNo, pageSize);
        Page<TableDTO> queryRet = this.mapper.queryModelByCond(topicId, keyWords, code, status);
        queryRespBean.setResult(queryRet);

        valueConvert(queryRet.getResult());

        return queryRespBean;
    }

    /**
     * 发布模型
     *
     * @param id
     * @return
     */
    @Transactional
    public boolean publishModel(String id) {
        if (StringUtils.isBlank(id)) {
            logger.warn("模型ID为空，发布失败");

            return false;
        }

        TableDTO queryRet = this.selectByPrimaryKey(id);
        if (queryRet == null) {
            throw new BusinessException("未找到模型，发布失败，id：" + id);
        }

        // 更新状态，包括模型状态、版本信息
        queryRet.setStatus(ModelState.PUBLISHED.getCode());
        queryRet.setModelVersion(getNextVersion(queryRet.getModelVersion()));
        this.updateByPrimaryKeySelective(queryRet);

        // TODO:保存模型信息；
        // TODO:保存字段信息；

        // TODO:模型落库；
        insertTable2Db(queryRet);

        return true;
    }

    /**
     * 启用停用
     *
     * @param id
     * @param status
     * @return
     */
    @Transactional
    public boolean updateStatus(String id, Integer status) {
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("模型ID为空");
        }
        if (status == null) {
            throw new BusinessException("状态为空");
        }

        TableDTO queryRet = this.selectByPrimaryKey(id);
        if (queryRet == null) {
            throw new BusinessException("未找到模型，启用或停用模型失败，id：" + id);
        }

        queryRet.setEnableStatus(status);
        this.updateByPrimaryKeySelective(queryRet);

        return true;
    }

    /**
     * 修订
     *
     * @param id
     * @return
     */
    public boolean reviseTable(String id) {
        if (StringUtils.isEmpty(id)) {
            throw new BusinessException("模型ID为空");
        }

        TableDTO queryRet = this.selectByPrimaryKey(id);
        if (queryRet == null) {
            throw new BusinessException("未找到模型，启用或停用模型失败，id：" + id);
        }

        queryRet.setStatus(ModelState.EDIT.getCode());
        this.updateByPrimaryKeySelective(queryRet);

        return true;
    }

    /**
     * 模型名称或编码是否重复
     *
     * @param modelId ID，编辑时修改名称，需要传入modelId;新增场景不需要传入
     * @param name    名称
     * @param code    编码
     * @return
     */
    public boolean isSameName(String modelId, String name, String code) {
        long count = this.mapper.selectNameCount(modelId, name, code);
        if (count > 0) {
            return true;
        }

        return false;
    }

    /**
     * 新增模型合法性检查
     *
     * @param tableDTO
     */
    private void checkAddValidity(TableDTO tableDTO) {
        if (tableDTO == null) {
            throw new BusinessException("入参为null");
        }

        if (StringUtils.isEmpty(tableDTO.getName())) {
            throw new BusinessException("名称为空");
        }

        if (StringUtils.isEmpty(tableDTO.getCode())) {
            throw new BusinessException("编码为空");
        }

        if (StringUtils.isEmpty(tableDTO.getTableName())) {
            throw new BusinessException("表名为空");
        }

        if (StringUtils.isEmpty(tableDTO.getTopicId())) {
            throw new BusinessException("模型ID为空");
        }

        if (tableDTO.getType() == null) {
            throw new BusinessException("模型类型为空");
        }
    }

    /**
     * 新增模型合法性检查
     *
     * @param tableDTO
     */
    private void checkUpdateValidity(TableDTO tableDTO) {
        if (tableDTO == null) {
            throw new BusinessException("入参为null");
        }

        if (StringUtils.isEmpty(tableDTO.getId())) {
            throw new BusinessException("主键为空");
        }
    }

    /**
     * 持久化到Db
     *
     * @param tableDTO
     * @return
     */
    private String saveModel2Db(TableDTO tableDTO) {
        if (tableDTO == null) {
            return null;
        }

        tableDTO.setId(ComUtil.getId());
        tableDTO.setStatus(ModelState.EDIT.getCode());
        this.insert(tableDTO);

        BdpLogUtil.log4Insert(tableDTO);

        return tableDTO.getId();
    }

    /**
     * 模型持久化到Db
     *
     * @param tableDTO
     * @return
     */
    private String updateModel2Db(TableDTO tableDTO) {
        if (tableDTO == null) {
            return null;
        }

        TableDTO oldDTO = this.mapper.selectByPrimaryKey(tableDTO.getId());
        if (oldDTO == null) {
            throw new BusinessException("未找到模型，id：" + tableDTO.getId());
        }

        this.updateByPrimaryKeySelective(tableDTO);

        BdpLogUtil.log4Update(tableDTO, oldDTO);

        return tableDTO.getId();
    }

    /**
     * 删除模型
     * 1、删除字段信息，包括字段、编码规则
     * 2、数据表（物理表）
     * 3、删除模型表
     *
     * @param id
     * @return
     */
    private int deleteModelInner(String id) {
        List<String> tableIdList = Arrays.asList(id.trim().split(Constants.COMMA));

        // 删除字段、删除数据表（物理表）
        if (CollectionUtils.isNotEmpty(tableIdList)) {
            for (String tableId : tableIdList) {
                // step1:删除字段
                TableDTO tableDTO = this.getModelDetail(tableId);
                String sql = this.commonService.getDropTableSql(tableDTO.getTableName());
                this.commonService.dropTable(tableDTO.getTableName(), sql);

                // step2:删除数据表（物理表）
                this.commonService.deleteColumnByTableId(tableId);
            }
        }

        // step3:删除模型
        return this.mapper.deleteModelByCond(Arrays.asList(id.trim().split(Constants.COMMA)));
    }

    /**
     * 获取版本信息
     * 注意：版本v1.0，下一个版本v1.1
     *
     * @param oldVersion
     * @return
     */
    private String getNextVersion(String oldVersion) {
        if (StringUtils.isEmpty(oldVersion)) {
            return Constants.VERSION_PREFIX + VersionUtil.generateVersion2Default();
        }

        String nextVersion = VersionUtil.generateVersion2Next(oldVersion.substring(1));
        return Constants.VERSION_PREFIX + nextVersion;
    }

    /**
     * 模型落库
     * 使用场景：发布模型时，模型落库并创建物理表
     * 限制说明：先删除旧表、再建新表，临时方案，简便快捷。
     *
     * @param tableDTO
     * @return
     */
    @SuppressWarnings("临时方案，后续优化")
    private void insertTable2Db(TableDTO tableDTO) {
        if (tableDTO == null) {
            throw new BusinessException("模型信息为空，发布失败");
        }

        List<ColumnDTO> columnList = this.columnService.getColumnList(tableDTO.getId());
        if (CollectionUtils.isEmpty(columnList)) {
            throw new BusinessException(String.format("模型中未设置字段，发布失败，tableId:%s，tableName:%s", tableDTO.getId(), tableDTO.getName()));
        }

        try {
            // 删除老表
            String sql = this.commonService.getDropTableSql(tableDTO.getTableName());
            this.commonService.dropTable(tableDTO.getTableName(), sql);

            // 创建新表
            this.commonService.createTable(tableDTO, columnList);
        } catch (Exception e) {
            throw new BusinessException("创建表失败", e);
        }
    }

    /**
     * 通过平台API将字段值转换为名称，包括通用选择组件、通用代码
     *
     * @param dtoList
     */
    private void valueConvert(List<TableDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }

        // 设置创建者名称
        Map<String, Set<String>> convertFormData = new HashMap<>();
        for (TableDTO dto : dtoList) {
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, dto.getCreatedBy());
        }
        if (convertFormData.size() > 0) {
            //获取请求结果
            Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
            //循环设置Alias或Name的值
            for (TableDTO dto : dtoList) {
                dto.setUserName(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, dto.getCreatedBy()));
            }
        }

        // 设置枚举值
        for (TableDTO dto : dtoList) {
            if (dto.getEnableStatus() != null) {
                dto.setEnableStatusName(EnableState.getDescByCode(dto.getStatus()));
            }
            if (dto.getStatus() != null) {
                dto.setStatusName(ModelState.getDescByCode(dto.getStatus()));
            }
            if (dto.getType() != null) {
                dto.setTypeName(ModelType.getDescByCode(dto.getStatus()));
            }
        }
    }
}
